package com.cunoraz.tagview;

import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.components.element.StateElement;
import ohos.agp.render.Canvas;
import ohos.agp.utils.Color;
import ohos.app.Context;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

public class TagView extends DependentLayout implements Component.DrawTask, Component.EstimateSizeListener, ComponentContainer.ArrangeListener {

    private final static String TAG = "TagView MainAbilitySlice";

    /**
     * tag list
     */
    private List<Tag> mTags = new ArrayList<>();

    /**
     * System Service
     */
    private LayoutScatter mInflater;

    /**
     * listeners
     */
    private OnTagClickListener mClickListener;
    private OnTagDeleteListener mDeleteListener;
    private OnTagLongClickListener mTagLongClickListener;

    /**
     * view size param
     */
    private int mWidth;

    /**
     * layout initialize flag
     */
    private boolean mInitialized = false;

    /**
     * custom layout param
     */
    private int lineMargin;
    private int tagMargin;
    private int textPaddingLeft;
    private int textPaddingRight;
    private int textPaddingTop;
    private int textPaddingBottom;
    private Context mContext;

    /**
     * constructor
     *
     * @param ctx
     * @param attrs
     */
    public TagView(Context ctx, AttrSet attrs) {
        super(ctx, attrs);
        initialize(ctx, attrs, "");
    }

    /**
     * constructor
     *
     * @param ctx
     * @param attrs
     * @param defStyle
     */
    public TagView(Context ctx, AttrSet attrs, String defStyle) {
        super(ctx, attrs, defStyle);
        initialize(ctx, attrs, defStyle);
    }

    /**
     * initalize instance
     *
     * @param ctx
     * @param attrs
     * @param defStyle
     */
    private void initialize(Context ctx, AttrSet attrs, String defStyle) {
        this.mContext = ctx;
        mInitialized = true;
        setArrangeListener(this::onArrange);
        setEstimateSizeListener(this::onEstimateSize);
        invalidate();
        this.lineMargin = (int)attrs.getAttr("lineMargin").get().getIntegerValue();
        this.tagMargin = (int)attrs.getAttr("tagMargin").get().getIntegerValue();
        this.textPaddingLeft = (int)attrs.getAttr("textPaddingLeft").get().getIntegerValue();
        this.textPaddingRight = (int)attrs.getAttr("textPaddingRight").get().getIntegerValue();
        this.textPaddingTop = (int)attrs.getAttr("textPaddingTop").get().getIntegerValue();
        this.textPaddingBottom = (int)attrs.getAttr("textPaddingBottom").get().getIntegerValue();
       // typeArray.recycle();
    }



    /**
     * onSizeChanged
     */
  /*  @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = getMeasuredWidth();
        if (width <= 0)
            return;
        mWidth = getMeasuredWidth();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }*/

    @Override
    public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {
        int wideSize = EstimateSpec.getSize(widthEstimateConfig);
        if (wideSize <= 0)
            return true;
        mWidth = wideSize;
        System.out.println("width------------" +mWidth);
        return false;
    }

    @Override
    public boolean onArrange(int left, int top, int width, int height) {
        mWidth = width;
        System.out.println(TAG + "-onArrange : " + mWidth);
        return false;
    }


    @Override
    public void invalidate() {
        super.invalidate();
        addDrawTask(this::onDraw);
    }



    @Override
    public void onDraw(Component component, Canvas canvas) {
        mWidth = component.getWidth();
        drawTags();
    }


    /**
     * tag draw
     */
    private void drawTags() {

        if (!mInitialized) {
            return;
        }

        // clear all tag
        removeAllComponents();

        // layout padding left & layout padding right
        float total = getPaddingLeft() + getPaddingRight();

        int listIndex = 1;// List Index
        int indexBottom = 1;// The Tag to add below
        int indexHeader = 1;// The header tag of this line
        Tag tagPre = null;
        System.out.println(TAG + "  -----item size:" +mTags.size());
        for (Tag item : mTags) {
            final int position = listIndex - 1;
            final Tag tag = item;
            System.out.println(TAG + "item :" +item.getText() );
            // inflate tag layout
            //View tagLayout = mInflater.inflate(R.layout.tagview_item, null);
            mInflater = LayoutScatter.getInstance(mContext);
            Component component = mInflater.parse(ResourceTable.Layout_tagview_item,null,true);
            component.setId(listIndex);
            component.setBackground(getSelector(tag));


            // tag text
            Text tagView = (Text) component.findComponentById(ResourceTable.Id_tv_tag_item_contain);
            tagView.setText(tag.getText());
            tagView.setTextSize(25);
            DirectionalLayout.LayoutConfig params = (DirectionalLayout.LayoutConfig) tagView.getLayoutConfig();
            params.setMargins(textPaddingLeft, textPaddingTop, textPaddingRight, textPaddingBottom);
            tagView.setLayoutConfig(params);
            tagView.setTextColor(new Color(tag.getTagTextColor()));
            tagView.setTextSize((int)tag.getTagTextSize(), Text.TextSizeType.FP);
            component.setClickedListener(new ClickedListener(){
                @Override
                public void onClick(Component component) {
                    if (mClickListener != null) {
                        mClickListener.onTagClick(tag, position);
                    }
                }
            });

            component.setLongClickedListener(new LongClickedListener() {
                @Override
                public void onLongClicked(Component component) {
                    if (mTagLongClickListener != null) {
                        mTagLongClickListener.onTagLongClick(tag, position);
                    }
                }

            });

            // calculate　of tag layout width
            //float tagWidth = tagView.getPaint().measureText(tag.getText()) + textPaddingLeft + textPaddingRight;

            int tagWidth = 150 + textPaddingLeft + textPaddingRight;
            // tagView padding (left & right)

            // deletable text
            Text deletableView = (Text) component.findComponentById(ResourceTable.Id_tv_tag_item_delete);

            if (tag.isDeletable()) {
                deletableView.setVisibility(Component.VISIBLE);
                deletableView.setText(tag.getDeleteIcon());
                int offset = (int)Utils.dip2px(getContext(), 2f);
                deletableView.setPadding(offset, textPaddingTop, textPaddingRight + offset, textPaddingBottom);
                deletableView.setTextColor(new Color(tag.getDeleteIndicatorColor()));
                deletableView.setTextSize((int)tag.getDeleteIndicatorSize(), Text.TextSizeType.FP);
                deletableView.setClickedListener(new ClickedListener() {
                    @Override
                    public void onClick(Component component) {
                        if (mDeleteListener != null) {
                            mDeleteListener.onTagDeleted(TagView.this, tag, position);
                        }
                    }
                });
                tagWidth += 150 + textPaddingLeft + textPaddingRight;
                // deletableView Padding (left & right)
            } else {
                deletableView.setVisibility(Component.HIDE);
            }
            LayoutConfig tagParams = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT, ComponentContainer.LayoutConfig.MATCH_CONTENT);
            tagParams.setMarginBottom(lineMargin);
            float testWidth = new BigDecimal(total).add(new BigDecimal(tagWidth))
                .add(new BigDecimal(Utils.dip2px(this.getContext(), Constants.LAYOUT_WIDTH_OFFSET))).floatValue();
            if (mWidth <= testWidth) {
                //need to add in new line
                if (tagPre != null) tagParams.addRule(LayoutConfig.BELOW, indexBottom);
                // initialize total param (layout padding left & layout padding right)
                total = getPaddingLeft() + getPaddingRight();
                indexBottom = listIndex;
                indexHeader = listIndex;
            } else {
                //no need to new line
                tagParams.addRule(LayoutConfig.ALIGN_TOP, indexHeader);
                if (listIndex != indexHeader) {
                    tagParams.addRule(LayoutConfig.RIGHT_OF, listIndex - 1);
                    tagParams.setMarginLeft(tagMargin);
                    total = new BigDecimal(total).add(new BigDecimal(tagMargin)).floatValue();
                    if (tagPre.getTagTextSize() < tag.getTagTextSize()) {
                        indexBottom = listIndex;
                    }
                }
            }
            total = new BigDecimal(total).add(new BigDecimal(tagWidth)).floatValue();
            addComponent(component,tagParams);
            tagPre = tag;
            listIndex++;

        }

    }

    private Element getSelector(Tag tag) {
        if (tag.getBackground() != null)
            return tag.getBackground();

        StateElement states = new StateElement();
        ShapeElement gdNormal = new ShapeElement();

        gdNormal.setRgbColor(RgbColor.fromArgbInt(tag.getLayoutColor()));
        gdNormal.setCornerRadius(tag.getRadius());
        if (tag.getLayoutBorderSize() > 0) {
            gdNormal.setStroke((int)Utils.dip2px(getContext(), tag.getLayoutBorderSize()), RgbColor.fromArgbInt(tag.getLayoutBorderColor()));
        }
        ShapeElement gdPress = new ShapeElement();
        gdPress.setRgbColor(RgbColor.fromArgbInt(tag.getLayoutColorPress()));
        gdPress.setCornerRadius(tag.getRadius());

        states.addState(new int[]{0,1},gdPress);

        //must add state_pressed first，or state_pressed will not take effect
        states.addState(new int[]{}, gdNormal);
        return states;
    }


    /**
     * 添加tag
     *
     * @param tag 文本标签
     */
    public void addTag(Tag tag) {
        mTags.add(tag);
        invalidate();
    }

    public void addTags(List<Tag> tags) {
        if (tags == null) return;
        mTags = new ArrayList<>();
        if (tags.isEmpty())
            invalidate();
        for (Tag item : tags) {
            mTags.add(item);
        }
        invalidate();
    }


    public void addTags(String[] tags) {
        if (tags == null) return;
        for (String item : tags) {
            Tag tag = new Tag(item);
            mTags.add(tag);
        }
        invalidate();
    }


    /**
     * get tag list
     *
     * @return mTags TagObject List
     */
    public List<Tag> getTags() {
        return mTags;
    }

    /**
     * remove tag
     *
     * @param position
     */
    public void remove(int position) {
        if (position < mTags.size()) {
            mTags.remove(position);
            invalidate();
        }
    }

    /**
     * remove all views
     */
    public void removeAll() {
        mTags.clear(); //clear all of tags
        removeAllComponents();
    }

    public int getLineMargin() {
        return lineMargin;
    }

    public void setLineMargin(float lineMargin) {
        this.lineMargin = (int)Utils.dip2px(getContext(), lineMargin);
    }

    public int getTagMargin() {
        return tagMargin;
    }

    public void setTagMargin(float tagMargin) {
        this.tagMargin = (int)Utils.dip2px(getContext(), tagMargin);
    }

    public int getTextPaddingLeft() {
        return textPaddingLeft;
    }

    public void setTextPaddingLeft(float textPaddingLeft) {
        this.textPaddingLeft = (int)Utils.dip2px(getContext(), textPaddingLeft);
    }

    public int getTextPaddingRight() {
        return textPaddingRight;
    }

    public void setTextPaddingRight(float textPaddingRight) {
        this.textPaddingRight = (int)Utils.dip2px(getContext(), textPaddingRight);
    }

    public int getTextPaddingTop() {
        return textPaddingTop;
    }

    public void setTextPaddingTop(float textPaddingTop) {
        this.textPaddingTop = (int)Utils.dip2px(getContext(), textPaddingTop);
    }

    public int gettextPaddingBottom() {
        return textPaddingBottom;
    }

    public void settextPaddingBottom(float textPaddingBottom) {
        this.textPaddingBottom = (int)Utils.dip2px(getContext(), textPaddingBottom);
    }


    /**
     * setter for OnTagLongClickListener
     *
     * @param longClickListener
     */
    public void setOnTagLongClickListener(OnTagLongClickListener longClickListener) {
        mTagLongClickListener = longClickListener;
    }

    /**
     * setter for OnTagSelectListener
     *
     * @param clickListener
     */
    public void setOnTagClickListener(OnTagClickListener clickListener) {
        mClickListener = clickListener;
    }

    /**
     * setter for OnTagDeleteListener
     *
     * @param deleteListener
     */
    public void setOnTagDeleteListener(OnTagDeleteListener deleteListener) {
        mDeleteListener = deleteListener;
    }




    /**
     * Listeners
     */
    public interface OnTagDeleteListener {
        void onTagDeleted(TagView view, Tag tag, int position);
    }

    public interface OnTagClickListener {
        void onTagClick(Tag tag, int position);
    }

    public interface OnTagLongClickListener {
        void onTagLongClick(Tag tag, int position);
    }
}
